/*
 * COPYRIGHT(c) SK telecom 2009
 * This software is the proprietary information of SK telecom.
 *
 * Revision History
 * Author             Date        Description
 * --------         ----------    ---------------
 *                  2012. 5. 31.  FTP 파일 전송
 *
 */
package com.tistory.commons.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.SocketException;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPConnectionClosedException;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.log4j.Logger;

/**
 * FTP로 접속 후 파일 전송
 */
public class FTPUtil {

	private final static Logger log = Logger.getLogger(FTPUtil.class);

	private FTPClient ftpClient = null;
	private String filepath = "";
	private String filename = "";
	private boolean result = true;
	private int checkCount = 0;
	private int replyCode = 0;
	private String workDir = "";

	/**
	 * 생성자
	 */
	public FTPUtil(String file_path, String file_name) {
		log.info("FTPSetting");
		this.ftpClient = new FTPClient();

		// windows server의 경로 구분자를 linux server의 경로 구분자로 변경 & VDS FTP Root 초기화
		this.filepath = (file_path.replace("\\", "/")).replaceAll("/data[0-9]*/", "/").replaceAll("/contents/", "/");
		this.filename = file_name;
		log.info("filepath : " + this.filepath);
		// log.info("filename : " + filename);
	}

	/**
	 * FTP 접속
	 * 
	 * @param id
	 * @param pw
	 */
	public boolean connectionFtp(String serverIP, Integer port) {
		log.info("connectionFtp to " + serverIP + " start!");
		this.result = true;
		this.checkCount = 0;
		try {
			if (!this.ftpClient.isConnected()) {
				do {
					this.ftpClient.connect(serverIP, port);
					this.replyCode = this.ftpClient.getReplyCode();
					log.info("Connection Reply Info  : " + this.ftpClient.getReplyString());
					this.checkCount++;
				} while (!FTPReply.isPositiveCompletion(this.replyCode) && this.checkCount < 3);

				// 0회 접속 실패 처리
				if (this.checkCount > 3)
					this.result = false;
			}
		} catch (FTPConnectionClosedException e) {
			this.result = false;
			log.info("Server Closed connection!!" + e);
		} catch (IOException e) {
			this.result = false;
			this.ftpDisconnect();
		}

		return this.result;
	}

	/**
	 * FTP FILE PATH 변경(DownLoad 후 Uploda시 필요)
	 * 
	 * @param id
	 * @param pw
	 */
	public void setFtpFilePath(String file_path) {
		log.info("setFtpFilePath start!");

		// windows server의 경로 구분자를 linux server의 경로 구분자로 변경 & VDS FTP Root 초기화
		this.filepath = (file_path.replace("\\", "/")).replaceAll("/data[0-9]*/", "/").replaceAll("/contents/", "/");
		log.info("filepath : " + this.filepath);
	}

	/**
	 * FTP 로그인
	 * 
	 * @param id
	 *            : 유저ID
	 * @param pw
	 *            : 비밀번호
	 */
	public boolean loginFtp(String id, String pw) {
		log.info("loginFtp start!");
		this.result = true;
		this.checkCount = 0;

		try {
			while (!this.ftpClient.login(id, pw) && this.checkCount < 3) {
				this.checkCount++;
			}

			// 3회 접속 실패 처리
			if (this.checkCount >= 3)
				this.result = false;
		} catch (SocketException e) {
			this.result = false;
			e.printStackTrace();
		} catch (IOException e) {
			this.result = false;
			e.printStackTrace();
		}

		return this.result;
	}

	/**
	 * FTP 환경 설정
	 */
	public void ftpSetting() {
		log.info("ftpSetting start!");

		String ftpConnectMode = "";

		try {
			ftpConnectMode = "passive";

			// ftpClient.setSoTimeout(10000);
			// 문자 코드를 UTF-8로 인코딩 설정 : 디폴트는 "ISO-8859-1"
			this.ftpClient.setControlEncoding("UTF-8");
			// 파일 형태 설정 : 디폴트는 ASCII
			this.ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
			// 전송 형태 설정 : 디폴트는 STREAM_TRANSFER_MODE
			this.ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
			// FTP 접속 Mode
			if (ftpConnectMode.equalsIgnoreCase("passive")) {
				this.ftpClient.enterLocalPassiveMode();
			} else {
				this.ftpClient.enterLocalActiveMode();
			}

		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * FTP 환경 설정
	 */
	public void ftpSettingIcms() {
		log.info("ftpSetting start!");

		String ftpConnectMode = "";

		try {

			ftpConnectMode = "passive";

			// ftpClient.setSoTimeout(10000);
			// 문자 코드를 UTF-8로 인코딩 설정 : 디폴트는 "ISO-8859-1"
			this.ftpClient.setControlEncoding("UTF-8");
			// 파일 형태 설정 : 디폴트는 ASCII
			this.ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
			// 전송 형태 설정 : 디폴트는 STREAM_TRANSFER_MODE
			this.ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
			// FTP 접속 Mode (통합CMS 는 Active)
			if (ftpConnectMode.equalsIgnoreCase("passive")) {
				this.ftpClient.enterLocalPassiveMode();
			} else {
				this.ftpClient.enterLocalActiveMode();
			}

		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * FTP 접속 해제
	 */
	public void ftpDisconnect() {
		log.info("ftpDisconnect start!");
		try {
			if (this.ftpClient.isConnected()) {
				log.info("Disconnect to Server!!");
				this.ftpClient.disconnect();
			}
		} catch (IOException e2) {
			// do Nothing
		}
	}

	/**
	 * 작업 디렉토리 설정
	 * 
	 * @return
	 */
	public boolean setWorkDirectory(String rootPath, String workType) {
		log.info("setWorkDirectory start!");

		this.result = true;
		String[] str = null;
		try {
			log.info("WorkDirectory1 : " + this.ftpClient.printWorkingDirectory());

			this.workDir = rootPath + this.filepath;
			this.result = this.ftpClient.changeWorkingDirectory(this.workDir);

			str = this.ftpClient.listNames();

			for (String aa : str) {
				log.info("#####" + aa);
			}

			log.info("workDir : " + this.workDir);
			log.info("result : " + this.result);

			if (!this.result && workType.equalsIgnoreCase("U")) {
				// root로 이동
				log.info("changeWorkingDirectory root!!");
				this.ftpClient.changeWorkingDirectory("/");
				// 작업 디렉토리 생성
				log.info("createFtpDirectoryTree!!");
				this.result = this.createFtpDirectoryTree(this.workDir);
			}

			str = this.ftpClient.listNames();
			for (String aa : str) {
				log.info("#####" + aa);
			}

			log.info("WorkDirectory2 : " + this.ftpClient.printWorkingDirectory());
		} catch (IOException e) {
			this.result = false;
			e.printStackTrace();
		}
		return this.result;
	}

	/**
	 * 작업 디렉토리 설정
	 * 
	 * @return
	 */
	public String[] getListNames(String workDirec) {
		log.info("getListNames start!");

		this.result = true;
		String[] str = null;
		try {

			this.result = this.ftpClient.changeWorkingDirectory(workDirec);

			log.info("WorkDirectory : " + this.ftpClient.printWorkingDirectory());
			log.info("result : " + this.result);

			str = this.ftpClient.listNames();

			// FTPFile[] list = this.ftpClient.listFiles();
			// FTPFile file;
			// for (int i = 0; i < list.length; i++) {
			// file = new FTPFile();
			// file = list[i];
			// str[i] = file.getName();
			// }

			for (String fileName : str) {
				log.info("##### fileName : " + fileName);
			}

			this.result = this.ftpClient.changeWorkingDirectory("res/backup");
			log.info("#WorkDirectory : " + this.ftpClient.printWorkingDirectory());
			log.info("#result : " + this.result);
			this.result = this.ftpClient.changeWorkingDirectory("backup");
			log.info("##WorkDirectory : " + this.ftpClient.printWorkingDirectory());
			log.info("##result : " + this.result);

		} catch (IOException e) {
			str = null;
			e.printStackTrace();
		}
		return str;
	}

	/**
	 * 작업 디렉토리 설정 (ICMS)
	 * 
	 * @return
	 */
	public boolean setWorkDirectory(String rootPath, String destPath, String workType) {
		// log.info("setWorkDirectory start!");

		this.result = true;
		try {
			log.info("WorkDirectory1 : " + this.ftpClient.printWorkingDirectory());

			this.workDir = rootPath + destPath;
			this.result = this.ftpClient.changeWorkingDirectory(this.workDir);

			if (!this.result && workType.equalsIgnoreCase("U")) {
				// root로 이동
				// log.info("changeWorkingDirectory root!!");
				this.ftpClient.changeWorkingDirectory("/");
				// 작업 디렉토리 생성
				log.info("createFtpDirectoryTree!!");
				this.result = this.createFtpDirectoryTree(this.workDir);

			}

			// log.info("WorkDirectory2 : " + ftpClient.printWorkingDirectory());

		} catch (IOException e) {
			this.result = false;
			e.printStackTrace();
		}
		return this.result;
	}

	/**
	 * 작업 디렉토리 file 삭제 (ICMS)
	 * 
	 * @return
	 */
	public boolean ftpDelete(String rootPath, String destPath, String workType) {
		log.info("ftpDelete start!");

		this.result = true;
		try {
			log.info("ftpDelete : " + this.ftpClient.printWorkingDirectory());

			this.workDir = rootPath + destPath;

			if (workType.equalsIgnoreCase("D")) {
				// directory delete
				log.info("deleteFtpDirectoryTree!!");

				if (!this.ftpClient.removeDirectory(this.workDir)) {
					log.info("deleteFtpDirectoryTree!! Fail");
				}
			}

			log.info("ftpDelete : " + this.ftpClient.printWorkingDirectory());

		} catch (IOException e) {
			this.result = false;
			e.printStackTrace();
		}
		return this.result;
	}

	/**
	 * 파일 업로드
	 * 
	 * @param srcFile
	 * @throws IOException
	 */
	public boolean uploadFile(File destFile) {
		log.info("uploadFile start!!");

		this.result = true;
		this.checkCount = 0;
		BufferedInputStream bis = null;

		try {
			bis = new BufferedInputStream(new FileInputStream(destFile));

			if (this.ftpClient != null) {
				while (this.checkCount < 3 && !this.ftpClient.storeFile(this.filename, bis)) {
					this.checkCount++;
				}
			}

			if (this.checkCount >= 3) {
				// 3회 파일 업로드 실패시 파일 삭제
				this.ftpClient.deleteFile(this.filename);
				this.result = false;
			}

		} catch (Exception e) {
			this.result = false;
			log.error(e);
			// } catch (FileNotFoundException e) {
			// result = false;
			// log.info("업로드할 파일이 없습니다.!!"+ e.getMessage());
			// log.info("업로드할 파일이 없습니다.!!"+ e.toString());
			// } catch (IOException e) {
			// result = false;
			// log.info("업로드 중 오류가 발생했습니다.!!" + e.getMessage());
			// log.info("업로드 중 오류가 발생했습니다.!!" + e.toString());
		} finally {
			if (bis != null) {
				try {
					bis.close();
				} catch (Exception e2) {
				}
			}
		}

		return this.result;
	}

	/**
	 * 파일 업로드
	 * 
	 * @param srcFile
	 * @throws IOException
	 */
	public boolean uploadFile(File destFile, String destFileName) {
		log.info("uploadFile start!!");

		this.result = true;
		this.checkCount = 0;
		BufferedInputStream bis = null;
		try {
			bis = new BufferedInputStream(new FileInputStream(destFile));

			if (this.ftpClient != null) {
				while (this.checkCount < 3 && !this.ftpClient.storeFile(destFileName, bis)) {
					this.checkCount++;
				}
			}

			/*
			 * if(ftpClient != null) { while(checkCount < 3 && !ftpClient.appendFile(destFileName, bis)) { checkCount++;
			 * } }
			 */

			if (this.checkCount >= 3) {
				// 3회 파일 업로드 실패시 파일 삭제
				this.ftpClient.deleteFile(destFileName);
				this.result = false;
			}

		} catch (Exception e) {
			this.result = false;
			log.error(e);
			// } catch (FileNotFoundException e) {
			// result = false;
			// log.info("업로드할 파일이 없습니다.!!"+ e.getMessage());
			// log.info("업로드할 파일이 없습니다.!!"+ e.toString());
			// } catch (IOException e) {
			// result = false;
			// log.info("업로드 중 오류가 발생했습니다.!!" + e.getMessage());
			// log.info("업로드 중 오류가 발생했습니다.!!" + e.toString());
		} finally {
			if (bis != null) {
				try {
					bis.close();
				} catch (Exception e2) {
				}
			}
		}

		return this.result;
	}

	/**
	 * 파일 업로드 디렉토리 이동후 삭제
	 * 
	 * @param srcFile
	 * @throws IOException
	 */
	public boolean uploadFileDelete(File destFile, String destFileName) {
		log.info("uploadFileDelete start!!");

		this.result = true;

		try {

			if (!this.ftpClient.deleteFile(destFileName)) {
				log.info("Failure to Detele file " + destFileName);
				this.result = false;
			}

		} catch (Exception e) {
			this.result = false;
			log.error(e);
		} finally {

		}

		return this.result;
	}

	/**
	 * 업로드 경로 삭제
	 * 
	 * @param srcFile
	 * @throws IOException
	 */
	public void uploadDirectoryRemove() throws IOException {
		log.info("uploadDirectoryRemove start!!");

		String removeDir = this.workDir;
		log.info("removeDir : " + removeDir);

	}

	/**
	 * 업로드 파일 삭제
	 * 
	 * @param srcFile
	 * @throws IOException
	 */
	public void uploadFileDelete() throws IOException {
		log.info("uploadFileDelete start!!");

		String[] ftpFiles = this.ftpClient.listNames();

		// 파일 경로가 최소한 32자 이상일 경우만 삭제
		if (this.workDir.length() > 32) {
			if (ftpFiles != null) {
				for (int i = 0; i < ftpFiles.length; i++) {
					log.info("VDS FTP File " + ftpFiles[i] + " Delete");
					this.ftpClient.deleteFile(ftpFiles[i]);
				}
			}
		} else {
			log.info("파일경로 확인이 필요합니다.");
		}

		// VDS FTP 미리보기 경로 삭제
		// uploadDirectoryRemove();
	}

	/**
	 * 파일 다운로드
	 * 
	 * @param srcFile
	 * @throws IOException
	 */
	public boolean downloadFile(File oldFile) throws IOException {
		log.info("downloadFile start!! ");

		this.result = true;
		BufferedOutputStream bos = null;
		try {
			// 원본(filename) => 복사본(oldFile)
			bos = new BufferedOutputStream(new FileOutputStream(oldFile));
			if (this.ftpClient != null)
				log.info("Download File Name : " + this.filename);
			this.result = this.ftpClient.retrieveFile(this.filename, bos);

			if (!this.result) {
				throw new IOException("Failuer Download File!!");
			}
			log.info("Success Download File");
		} catch (FileNotFoundException e) {
			this.result = false;
			log.info(e.toString());
		} catch (IOException e) {
			this.result = false;
			log.info(e.toString());
		} finally {
			if (bos != null) {
				try {
					bos.close();
				} catch (Exception e2) {
				}
			}
		}

		return this.result;
	}

	/**
	 * 파일 다운로드
	 * 
	 * @param srcFile
	 * @throws IOException
	 */
	public boolean downloadFile(File oldFile, String oldFileName) throws IOException {
		log.info("downloadFile start!! ");

		this.result = true;
		BufferedOutputStream bos = null;
		try {
			// 원본(filename) => 복사본(oldFile)
			bos = new BufferedOutputStream(new FileOutputStream(oldFile));
			if (this.ftpClient != null)
				this.result = this.ftpClient.retrieveFile(oldFileName, bos);

			if (!this.result) {
				throw new IOException("Failuer Download File!!");
			}
			log.info("Success Download File");
		} catch (FileNotFoundException e) {
			this.result = false;
			log.info(e.toString());
		} catch (IOException e) {
			this.result = false;
			log.info(e.toString());
		} finally {
			if (bos != null) {
				try {
					bos.close();
				} catch (Exception e2) {
				}
			}
		}

		return this.result;
	}

	/**
	 * Upload Directory Create
	 */
	public boolean createFtpDirectoryTree(String workDir) {
		// log.info("createFtpDirectoryTree start!");

		boolean dirExists = true;
		this.result = true;
		String[] directories = workDir.split("/");

		for (String dir : directories) {
			// log.info("dir : " + dir);
			if (!"".equalsIgnoreCase(dir)) {
				try {
					// log.info("changeWorkingDirectory!!");
					dirExists = this.ftpClient.changeWorkingDirectory(dir);
					if (!dirExists) {
						log.info("makeDirectory!!");
						if (!this.ftpClient.makeDirectory(dir)) {
							throw new IOException("Unable to create remote directory '" + dir + "'.  error='"
									+ this.ftpClient.getReplyString() + "'");
						}
						// log.info("changeWorkingDirectory!!");
						if (!this.ftpClient.changeWorkingDirectory(dir)) {
							throw new IOException("Unable to change into newly created remote directory '" + dir
									+ "'.  error='" + this.ftpClient.getReplyString() + "'");
						}
					}
				} catch (IOException e) {
					this.result = false;
					log.info("디렉토리 생성에 실패하였습니다!!!" + e.toString());
				}
			}
		}
		return this.result;
	}

	/**
	 * FTP 로그아웃
	 */
	public void logoutFtp() {
		log.info("logoutFtp start!");

		try {
			if (!this.ftpClient.logout()) {
				throw new IOException("logout fail!! " + ".  error = " + this.ftpClient.getReplyString() + "'");
			}
		} catch (IOException e) {
			log.info(e.toString());
		}
	}
}
